package net.minecraft.client;

import com.mega.timestop.EventUtil;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiSleepMP;
import net.minecraft.client.gui.ScaledResolution;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderItem;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.chunk.RenderChunk;
import net.minecraft.client.renderer.entity.RenderEntityItem;
import net.minecraft.client.renderer.entity.layers.LayerArmorBase;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraft.crash.ICrashReportDetail;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.EnumDifficulty;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;

import java.io.IOException;

public class RunGameLoop {
    static Minecraft mc = Minecraft.getMinecraft();
    private static final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");

    public static void replaceItemRenders(Minecraft mc) {
        mc.renderItem = new RenderItem(mc.renderEngine, mc.renderItem.getItemModelMesher().getModelManager(), mc.getItemColors()) {
            @Override
            public void renderEffect(IBakedModel model) {
                GlStateManager.depthMask(false);
                GlStateManager.depthFunc(514);
                GlStateManager.disableLighting();
                GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_COLOR, GlStateManager.DestFactor.ONE);
                mc.renderEngine.bindTexture(RES_ITEM_GLINT);
                GlStateManager.matrixMode(5890);
                GlStateManager.pushMatrix();
                GlStateManager.scale(8.0F, 8.0F, 8.0F);
                float f = (float) (Minecraft.getSystemTime() % 3000L) / 3000.0F / 8.0F;
                if (!EventUtil.timeStop)
                    GlStateManager.translate(f, 0.0F, 0.0F);
                GlStateManager.rotate(-50.0F, 0.0F, 0.0F, 1.0F);
                this.renderModel(model, -8372020);
                GlStateManager.popMatrix();
                GlStateManager.pushMatrix();
                GlStateManager.scale(8.0F, 8.0F, 8.0F);
                float f1 = (float) (Minecraft.getSystemTime() % 4873L) / 4873.0F / 8.0F;
                if (!EventUtil.timeStop)
                    GlStateManager.translate(-f1, 0.0F, 0.0F);
                GlStateManager.rotate(10.0F, 0.0F, 0.0F, 1.0F);
                this.renderModel(model, -8372020);
                GlStateManager.popMatrix();
                GlStateManager.matrixMode(5888);
                GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
                GlStateManager.enableLighting();
                GlStateManager.depthFunc(515);
                GlStateManager.depthMask(true);
                //mc.renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
            }
        };
        mc.ingameGUI.itemRenderer = mc.renderItem;
        mc.getTutorial().reload();
        mc.entityRenderer.itemRenderer.itemRenderer = mc.renderItem;
        ((RenderEntityItem) mc.getRenderManager().entityRenderMap.get(EntityItem.class)).itemRenderer = mc.renderItem;
    }

    public static void runGameLoop() throws IOException {
        mc.isGamePaused = EventUtil.timeStop;
        replaceItemRenders(mc);
        long i = System.nanoTime();
        mc.mcProfiler.startSection("root");
        if (Display.isCreated() && Display.isCloseRequested()) {
            mc.shutdown();
        }
        mc.mcProfiler.startSection("scheduledExecutables");
        mc.mcProfiler.endSection();
        long l = System.nanoTime();
        mc.mcProfiler.startSection("tick");
        for (int j = 0; j < Math.min(10, mc.timer.elapsedTicks); ++j) {
            runTick();
        }
        mc.mcProfiler.endStartSection("preRenderErrors");
        long i1 = System.nanoTime() - l;
        mc.checkGLError("Pre render");
        mc.mcProfiler.endStartSection("sound");
        if (mc.getRenderViewEntity() != null)
            mc.getSoundHandler().setListener(mc.getRenderViewEntity(), mc.timer.renderPartialTicks); //Forge: MC-46445 Spectator mode particles and sounds computed from where you have been before
        mc.mcProfiler.endSection();
        mc.mcProfiler.startSection("render");
        GlStateManager.pushMatrix();
        GlStateManager.clear(16640);
        mc.getFramebuffer().bindFramebuffer(true);
        mc.mcProfiler.startSection("display");
        GlStateManager.enableTexture2D();
        mc.mcProfiler.endSection();
        net.minecraftforge.fml.common.FMLCommonHandler.instance().onRenderTickStart(mc.timer.renderPartialTicks);
        mc.mcProfiler.endStartSection("gameRenderer");
        mc.entityRenderer.updateCameraAndRender(EventUtil.timeStop ? mc.renderPartialTicksPaused : mc.timer.renderPartialTicks, i);
        mc.mcProfiler.endStartSection("toasts");mc.getToastGui().drawToast(new ScaledResolution(mc));
        mc.mcProfiler.endSection();
        net.minecraftforge.fml.common.FMLCommonHandler.instance().onRenderTickEnd(mc.timer.renderPartialTicks);
        mc.mcProfiler.endSection();
        if (mc.gameSettings.showDebugInfo && mc.gameSettings.showDebugProfilerChart && !mc.gameSettings.hideGUI) {
            if (!mc.mcProfiler.profilingEnabled) {
                mc.mcProfiler.clearProfiling();
            }
            mc.mcProfiler.profilingEnabled = true;
            mc.displayDebugInfo(i1);
        } else {
            mc.mcProfiler.profilingEnabled = false;
            mc.prevFrameTime = System.nanoTime();
        }
        mc.getFramebuffer().unbindFramebuffer();
        GlStateManager.popMatrix();
        GlStateManager.pushMatrix();
        mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight);
        GlStateManager.popMatrix();
        GlStateManager.pushMatrix();
        mc.entityRenderer.renderStreamIndicator(mc.timer.renderPartialTicks);
        GlStateManager.popMatrix();
        mc.mcProfiler.startSection("root");
        mc.updateDisplay();
        Thread.yield();
        mc.checkGLError("Post render");
        mc.fpsCounter = -2147483647;
        mc.renderPartialTicksPaused = mc.timer.renderPartialTicks;
        long k = System.nanoTime();
        mc.frameTimer.addFrame(k - mc.startNanoTime);
        mc.startNanoTime = k;
        while (mc.systemTime >= mc.debugUpdateTime + 1000L) {
            Minecraft.debugFPS = mc.fpsCounter;
            mc.debug = String.format("%d fps (%d chunk update%s) T: %s%s%s%s%s", Minecraft.getDebugFPS(), RenderChunk.renderChunksUpdated, RenderChunk.renderChunksUpdated == 1 ? "" : "s", (float) mc.gameSettings.limitFramerate == GameSettings.Options.FRAMERATE_LIMIT.getValueMax() ? "inf" : mc.gameSettings.limitFramerate, mc.gameSettings.enableVsync ? " vsync" : "", mc.gameSettings.fancyGraphics ? "" : " fast", mc.gameSettings.clouds == 0 ? "" : (mc.gameSettings.clouds == 1 ? " fast-clouds" : " fancy-clouds"), OpenGlHelper.useVbo() ? " vbo" : "");
            RenderChunk.renderChunksUpdated = 0;
            mc.debugUpdateTime += 1000L;
            mc.fpsCounter = 0;
            mc.usageSnooper.addMemoryStatsToSnooper();
            if (!mc.usageSnooper.isSnooperRunning()) {
                mc.usageSnooper.startSnooper();
            }
        }
        if (mc.isFramerateLimitBelowMax()) {
            mc.mcProfiler.startSection("fpslimit_wait");
            Display.sync(mc.getLimitFramerate());
            mc.mcProfiler.endSection();
        }
        if (mc.player != null) {
            mc.player.ticksExisted = (int)-mc.getRenderPartialTicks();
            for (Entity e : mc.world.loadedEntityList)
                if (e instanceof EntityLivingBase)
                    e.ticksExisted = (int)-mc.getRenderPartialTicks();
            runTickKeyboard();
            mc.runTickMouse();
            mc.world.updateEntity(mc.player);
        }
        mc.timer.renderPartialTicks = 0;
        mc.mcProfiler.endSection();
    }
    public static void runTick() throws IOException {
        if (mc.rightClickDelayTimer > 0) {
            --mc.rightClickDelayTimer;
        }
        net.minecraftforge.fml.common.FMLCommonHandler.instance().onPreClientTick();
        mc.mcProfiler.startSection("gui");
        mc.mcProfiler.endSection();
        mc.entityRenderer.getMouseOver(1.0F);
        mc.getTutorial().onMouseHover(mc.world, mc.objectMouseOver);
        mc.mcProfiler.startSection("gameMode");
        mc.mcProfiler.endStartSection("textures");
        if (mc.currentScreen == null && mc.player != null) {
            if (mc.player.getHealth() <= 0.0F && !(mc.currentScreen instanceof GuiGameOver)) {
                mc.displayGuiScreen(null);
            } else if (mc.player.isPlayerSleeping() && mc.world != null) {
                mc.displayGuiScreen(new GuiSleepMP());
            }
        } else if (mc.currentScreen instanceof GuiSleepMP && !mc.player.isPlayerSleeping()) {
            mc.displayGuiScreen(null);
        }
        if (mc.currentScreen != null) {
            mc.leftClickCounter = 10000;
        }
        if (mc.currentScreen != null) {
            try {
                mc.currentScreen.handleInput();
            } catch (Throwable throwable1) {
                CrashReport crashreport = CrashReport.makeCrashReport(throwable1, "Updating screen events");
                CrashReportCategory crashreportcategory = crashreport.makeCategory("Affected screen");
                crashreportcategory.addDetail("Screen name", new ICrashReportDetail<String>() {
                    public String call() throws Exception {
                        return mc.currentScreen.getClass().getCanonicalName();
                    }
                });
                throw new ReportedException(crashreport);
            }
        }
        if (mc.currentScreen == null || mc.currentScreen.allowUserInput) {
            mc.mcProfiler.endStartSection("mouse");
            mc.runTickMouse();
            if (mc.leftClickCounter > 0) {
                --mc.leftClickCounter;
            }
            mc.mcProfiler.endStartSection("keyboard");
            runTickKeyboard();
        }
        if (mc.world != null) {
            if (mc.player != null) {
                ++mc.joinPlayerCounter;

                if (mc.joinPlayerCounter == 30) {
                    mc.joinPlayerCounter = 0;
                    mc.world.joinEntityInSurroundings(mc.player);
                }
            }
            mc.mcProfiler.endStartSection("gameRenderer");
            mc.mcProfiler.endStartSection("levelRenderer");
            mc.mcProfiler.endStartSection("level");
        } else if (mc.entityRenderer.isShaderActive()) {
            mc.entityRenderer.stopUseShader();
        }
        if (mc.world != null) {
            if (!EventUtil.timeStop) {
                mc.world.setAllowedSpawnTypes(mc.world.getDifficulty() != EnumDifficulty.PEACEFUL, true);
                mc.getTutorial().update();
            }
            mc.mcProfiler.endStartSection("animateTick");
            mc.mcProfiler.endStartSection("particles");
        } else if (mc.myNetworkManager != null) {
            mc.mcProfiler.endStartSection("pendingConnection");
            mc.myNetworkManager.processReceivedPackets();
        }

        mc.mcProfiler.endSection();
        net.minecraftforge.fml.common.FMLCommonHandler.instance().onPostClientTick();
        mc.systemTime = Minecraft.getSystemTime();
    }

    public static void runTickKeyboard() throws IOException {
        while (Keyboard.next()) {
            int i = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();

            if (mc.debugCrashKeyPressTime > 0L) {
                if (Minecraft.getSystemTime() - mc.debugCrashKeyPressTime >= 6000L) {
                    throw new ReportedException(new CrashReport("Manually triggered debug crash", new Throwable()));
                }

                if (!Keyboard.isKeyDown(46) || !Keyboard.isKeyDown(61)) {
                    mc.debugCrashKeyPressTime = -1L;
                }
            } else if (Keyboard.isKeyDown(46) && Keyboard.isKeyDown(61)) {
                mc.actionKeyF3 = true;
                mc.debugCrashKeyPressTime = Minecraft.getSystemTime();
            }

            mc.dispatchKeypresses();

            if (mc.currentScreen != null) {
                mc.currentScreen.handleKeyboardInput();
            }

            boolean flag = Keyboard.getEventKeyState();

            if (flag) {
                if (i == 62 && mc.entityRenderer != null) {
                    mc.entityRenderer.switchUseShader();
                }

                boolean flag1 = false;

                if (mc.currentScreen == null) {
                    if (i == 1) {
                        mc.displayInGameMenu();
                    }

                    flag1 = Keyboard.isKeyDown(61) && mc.processKeyF3(i);
                    mc.actionKeyF3 |= flag1;

                    if (i == 59) {
                        mc.gameSettings.hideGUI = !mc.gameSettings.hideGUI;
                    }
                }

                if (flag1) {
                    KeyBinding.setKeyBindState(i, false);
                } else {
                    KeyBinding.setKeyBindState(i, true);
                    KeyBinding.onTick(i);
                }

                if (mc.gameSettings.showDebugProfilerChart) {
                    if (i == 11) {
                        mc.updateDebugProfilerName(0);
                    }

                    for (int j = 0; j < 9; ++j) {
                        if (i == 2 + j) {
                            mc.updateDebugProfilerName(j + 1);
                        }
                    }
                }
            } else {
                KeyBinding.setKeyBindState(i, false);

                if (i == 61) {
                    if (mc.actionKeyF3) {
                        mc.actionKeyF3 = false;
                    } else {
                        mc.gameSettings.showDebugInfo = !mc.gameSettings.showDebugInfo;
                        mc.gameSettings.showDebugProfilerChart = mc.gameSettings.showDebugInfo && GuiScreen.isShiftKeyDown();
                        mc.gameSettings.showLagometer = mc.gameSettings.showDebugInfo && GuiScreen.isAltKeyDown();
                    }
                }
            }
            net.minecraftforge.fml.common.FMLCommonHandler.instance().fireKeyInput();
        }

        mc.processKeyBinds();
    }
}
